#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
线程安全日志模块

提供线程安全的日志记录功能，支持多线程环境下的日志输出，包含线程ID和线程名称
支持日志文件按启动时间命名、自动创建log目录、文件大小限制和自动分割
"""

import datetime
import logging
import os
import sys
import threading
from logging.handlers import RotatingFileHandler
from typing import Optional


class Logger:
    """
    线程安全的日志类
    
    封装了Python的logging模块，提供线程安全的日志记录功能
    支持日志文件按启动时间命名、自动创建log目录、文件大小限制和自动分割
    """
    
    # 全局锁，确保日志配置的线程安全
    _config_lock = threading.RLock()
    
    def __init__(self, log_file: str = None, log_level: str = 'INFO', 
                 max_bytes: int = 50 * 1024 * 1024, backup_count: int = 5):
        """
        初始化日志记录器
        
        Args:
            log_file: 日志文件路径，如果为None则使用默认路径（log目录+启动时间）
            log_level: 日志级别（DEBUG, INFO, WARNING, ERROR, CRITICAL）
            max_bytes: 单个日志文件最大字节数，默认50MB
            backup_count: 保留的备份文件数量，默认5个
        """
        # 生成默认日志文件路径（log目录+启动时间）
        if log_file is None:
            # 获取当前时间作为日志文件名的一部分
            startup_time = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
            log_filename = f"db_sync_{startup_time}.log"
            
            # 创建log目录（在工程根目录下）
            # 根据用户需求，获取入口程序文件所在路径
            entry_point = os.path.abspath(sys.argv[0])
            # 获取入口程序所在目录
            entry_dir = os.path.dirname(entry_point)
            # 在入口程序目录下创建log文件夹
            log_dir = os.path.join(entry_dir, 'log')
            if not os.path.exists(log_dir):
                os.makedirs(log_dir)
            
            # 完整的日志文件路径
            log_file = os.path.join(log_dir, log_filename)
        
        self.log_file = log_file
        self.log_level = log_level
        self.max_bytes = max_bytes
        self.backup_count = backup_count
        
        # 获取日志级别对应的数值
        level_value = getattr(logging, log_level.upper(), logging.INFO)
        
        with self._config_lock:
            # 创建或获取logger实例
            self.logger = logging.getLogger(__name__)
            self.logger.setLevel(level_value)
            
            # 避免重复添加handler
            if not self.logger.handlers:
                # 创建RotatingFileHandler，支持文件大小限制和自动分割
                file_handler = RotatingFileHandler(
                    log_file, 
                    maxBytes=max_bytes, 
                    backupCount=backup_count, 
                    encoding='utf-8'
                )
                file_handler.setLevel(level_value)
                
                # 创建控制台handler
                console_handler = logging.StreamHandler(sys.stdout)
                console_handler.setLevel(level_value)
                
                # 定义日志格式
                # 包含线程ID和线程名称的格式
                log_format = ('%(asctime)s | %(threadName)s | %(levelname)s | %(lineno)d | %(message)s')
                formatter = logging.Formatter(log_format, datefmt='%Y-%m-%d %H:%M:%S')
                
                # 设置handler的格式
                file_handler.setFormatter(formatter)
                console_handler.setFormatter(formatter)
                
                # 添加handler到logger
                self.logger.addHandler(file_handler)
                self.logger.addHandler(console_handler)
                
                # 记录日志文件路径信息
                self.logger.info(f"日志文件路径: {log_file}")
                self.logger.info(f"日志文件大小限制: {max_bytes // (1024*1024)}MB, 备份数量: {backup_count}")
    
    def debug(self, message: str):
        """
        记录DEBUG级别的日志
        
        Args:
            message: 日志消息
        """
        self.logger.debug(message, stacklevel=2)
    
    def info(self, message: str):
        """
        记录INFO级别的日志
        
        Args:
            message: 日志消息
        """
        self.logger.info(message, stacklevel=2)
    
    def warning(self, message: str):
        """
        记录WARNING级别的日志
        
        Args:
            message: 日志消息
        """
        self.logger.warning(message, stacklevel=2)
    
    def error(self, message: str):
        """
        记录ERROR级别的日志
        
        Args:
            message: 日志消息
        """
        self.logger.error(message, stacklevel=2)
    
    def critical(self, message: str):
        """
        记录CRITICAL级别的日志
        
        Args:
            message: 日志消息
        """
        self.logger.critical(message, stacklevel=2)
    
    def log_exception(self, exception: Exception, message: str = None):
        """
        记录异常信息
        
        Args:
            exception: 异常对象
            message: 可选的附加消息
        """
        if message:
            self.logger.error(f"{message}: {str(exception)}", exc_info=True, stacklevel=2)
        else:
            self.logger.error(str(exception), exc_info=True, stacklevel=2)
    
    def change_log_level(self, log_level: str):
        """
        动态更改日志级别
        
        Args:
            log_level: 新的日志级别
        """
        level_value = getattr(logging, log_level.upper(), logging.INFO)
        
        with self._config_lock:
            self.log_level = log_level
            self.logger.setLevel(level_value)
            
            # 更新所有handler的日志级别
            for handler in self.logger.handlers:
                handler.setLevel(level_value)
    
    def close(self):
        """
        关闭日志记录器，释放资源
        """
        with self._config_lock:
            for handler in self.logger.handlers:
                handler.close()
                self.logger.removeHandler(handler)


# 创建全局日志对象实例
# 可在模块中直接使用的默认日志实例
# 不指定log_file，使用默认的按时间命名的日志文件
# 单个文件最大50MB，最多保留5个备份
default_logger = Logger(log_level='INFO', max_bytes=50*1024*1024, backup_count=5)


# 便捷函数，直接使用默认日志实例
def debug(message: str):
    """
    使用默认日志实例记录DEBUG级别的日志
    """
    default_logger.logger.debug(message, stacklevel=2)

def info(message: str):
    """
    使用默认日志实例记录INFO级别的日志
    """
    default_logger.logger.info(message, stacklevel=2)

def warning(message: str):
    """
    使用默认日志实例记录WARNING级别的日志
    """
    default_logger.logger.warning(message, stacklevel=2)

def error(message: str):
    """
    使用默认日志实例记录ERROR级别的日志
    """
    default_logger.logger.error(message, stacklevel=2)

def critical(message: str):
    """
    使用默认日志实例记录CRITICAL级别的日志
    """
    default_logger.logger.critical(message, stacklevel=2)

def log_exception(exception: Exception, message: str = None):
    """
    使用默认日志实例记录异常信息
    """
    if message:
        default_logger.logger.error(f"{message}: {str(exception)}", exc_info=True, stacklevel=2)
    else:
        default_logger.logger.error(str(exception), exc_info=True, stacklevel=2)